/**
 * Created by Jorken on 23/05/21.
 */

import dayjs from 'dayjs'
import CryptoJS from 'crypto-js'
import { isObject } from './general'

// 防抖函数
export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result

  const later = function () {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }

  return function (...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在，重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }

    return result
  }
}

// 深拷贝
export function deepClone(target, map = new Map()) {
  // 非引用类型
  if (!isObject(target)) return target
  // 循环引用
  if (map.get(target)) return map.get(target)
  // 函数
  if (target instanceof Function) {
    return function () {
      return target.apply(this, arguments)
    }
  }
  // 日期
  if (target instanceof Date) return new Date(target)
  // 正则
  if (target instanceof RegExp) return new RegExp(target.source, target.flags)
  // 数组、对象
  let targetClone = Array.isArray(target) ? [] : {}
  map.set(target, targetClone)
  Object.keys(target).forEach(key => {
    if (typeof target[key] === 'object') {
      targetClone[key] = deepClone(target[key], map)
    } else {
      targetClone[key] = target[key]
    }
  })
  return targetClone
}

// 基础类型数据的数组去重
export function uniqueArray(arr) {
  return Array.from(new Set(arr))
}

// 判断元素是否有class
export function hasClass(ele, cls) {
  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
}

// 给元素添加class
export function addClass(ele, cls) {
  if (!hasClass(ele, cls)) ele.className += ' ' + cls
}

// 移除元素的class
export function removeClass(ele, cls) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
    ele.className = ele.className.replace(reg, ' ')
  }
}

// 切换元素的class
export function toggleClass(element, className) {
  if (!element || !className) {
    return
  }
  let classString = element.className
  const nameIndex = classString.indexOf(className)
  if (nameIndex === -1) {
    classString += '' + className
  } else {
    classString =
      classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length)
  }
  element.className = classString
}

// 格式化日期
export function formatDate(time) {
  const timeNumArr = time && time.toString().split('')
  timeNumArr.splice(4, 0, '-')
  timeNumArr.splice(7, 0, '-')
  return timeNumArr.join('')
}

// 格式化unix时间
export function formatUnixTime(time) {
  return time ? dayjs.unix(time).format('YYYY-MM-DD HH:mm:ss') : '--'
}

// 当天的起始时间戳
export function startStamp(date) {
  const timeStamp = date ? dayjs(date).startOf('day').valueOf() : Date.now()
  return Number(timeStamp)
}

// 当天的结束时间戳
export function endStamp(date) {
  const timeStamp = date ? dayjs(date).endOf('day').valueOf() : Date.now()
  return Number(timeStamp)
}

// 格式化文件路径
export function resolveUrl(originUrl) {
  const baseUrl = process.env.VUE_APP_BASE_URL
  if (originUrl.startsWith('http://') || originUrl.startsWith('https://')) {
    return originUrl
  } else {
    return baseUrl + originUrl
  }
}

// dataUrl转为File
export function dataUrltoFile(dataUrl, fileName) {
  var arr = dataUrl.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]),
    n = bstr.length,
    u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new File([u8arr], fileName, { type: mime })
}

// url转base64
export function urlToBase64(url) {
  return new Promise((resolve, reject) => {
    let image = new Image()
    image.onload = function () {
      let canvas = document.createElement('canvas')
      canvas.width = this.naturalWidth
      canvas.height = this.naturalHeight
      // 将图片插入画布并开始绘制
      canvas.getContext('2d').drawImage(image, 0, 0)
      // result
      let result = canvas.toDataURL('image/png')
      resolve(result)
    }
    image.setAttribute('crossOrigin', 'Anonymous')
    image.src = url
    // 图片加载失败的错误处理
    image.onerror = () => {
      reject(new Error('转换失败'))
    }
  })
}

// 格式化文件大小单位显示
export function formatFlowSize(oSize, radix = 2) {
  const size = Math.abs(oSize || 0)
  let result = oSize || 0

  if (size < 1024) {
    result = `${size} B`
  } else if (size >= 1024 && size < 1048576) {
    result = `${(size / 1024).toFixed(radix)} K`
  } else if (size >= 1048576 && size < 1073741824) {
    result = `${(size / 1048576).toFixed(radix)} M`
  } else if (size >= 1073741824 && size < 1099511627776) {
    result = `${(size / 1073741824).toFixed(radix)} G`
  } else {
    result = `${(size / 1099511627776).toFixed(radix)} T`
  }
  return `${oSize >= 0 ? '' : '-'}${result}`
}

// 生成Uuid
export function generateUuid(len, radix) {
  let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
  let uuid = [],
    i
  radix = radix || chars.length

  if (len) {
    // Compact form
    for (i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)]
  } else {
    let r
    for (i = 0; i < 36; i++) {
      if (!uuid[i]) {
        r = 0 | (Math.random() * 16)
        uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r]
      }
    }
  }
  return uuid.join('')
}

// 加密数据
export function encrypt(dataStr, keyStr = 'NdjBqhoiJ6lX52DU', ivStr = 'nak5iqTaudVXCCH2') {
  const key = CryptoJS.enc.Utf8.parse(keyStr)
  const iv = CryptoJS.enc.Utf8.parse(ivStr)
  let encrypted = CryptoJS.AES.encrypt(dataStr, key, { iv: iv })
  return encrypted.ciphertext.toString(CryptoJS.enc.Base64)
}
